package cmp.compile.panels;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.sql.ResultSet;
import java.util.Vector;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.plaf.ScrollBarUI;
import javax.swing.plaf.basic.BasicScrollBarUI;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;

import cmp.compile.CompileMain;
import cmp.compile.Summary;
import assem.DBConn;
import cmp.main.Globals;

import util.Debug.ErrorReport;

public class MethodPanel extends JPanel {
	private static final long serialVersionUID = -8287618156963989136L;

	public MethodPanel(CompilePanel parentPanel) {
		theParentPanel = parentPanel;
		
		setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
		setAlignmentX(Component.LEFT_ALIGNMENT);
		
		theTable = new MethodTable();
		theTable.setBackground(Globals.BGCOLOR);
		theTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
			public void valueChanged(ListSelectionEvent arg0) {
				updateTableButtons();
			}
		});

		
		lblMethods = new JLabel("3. Cluster Methods");

		btnAdd = new JButton("Add");
		btnAdd.setBackground(Globals.MENUCOLOR);
		btnAdd.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				theParentPanel.getEditMethodPanel().resetSettings();
				theParentPanel.setMainPanelVisible(false);
				theParentPanel.getEditMethodPanel().setLoaded(false);
				theParentPanel.getEditMethodPanel().setEditMode(false);
				theParentPanel.getEditMethodPanel().setLoaded(false);
				theParentPanel.getEditMethodPanel().setVisible(true);
			}
		});
		btnEdit = new JButton("Edit");
		btnEdit.setBackground(Globals.MENUCOLOR);
		btnEdit.setEnabled(false);
		btnEdit.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				int row = theTable.getSelectedRow();
				theParentPanel.getEditMethodPanel().setMethodType(theTable.getMethodTypeAt(row));
				theParentPanel.getEditMethodPanel().setMethodName(theTable.getMethodNameAt(row));
				theParentPanel.getEditMethodPanel().setPrefix(theTable.getPrefixAt(row));
				theParentPanel.getEditMethodPanel().setComment(theTable.getCommentAt(row));
				theParentPanel.getEditMethodPanel().setSettings(theTable.getSettingsAt(row));
				theParentPanel.setMainPanelVisible(false);
				theParentPanel.getEditMethodPanel().setLoaded(theTable.getLoadedAt(row));
				theParentPanel.getEditMethodPanel().setEditMode(true);
				theParentPanel.getEditMethodPanel().setVisible(true);
			}
		});
		btnRemove = new JButton("Remove");
		btnRemove.setBackground(Globals.BGCOLOR);
		btnRemove.setEnabled(false);
		btnRemove.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				try {
					Object [] optionsLoaded = { "Remove from database", "Remove from database and table" };
					
					int row = theTable.getSelectedRow();
					String methodName = theTable.getMethodNameAt(row);
					String prefixName = theTable.getPrefixAt(row);

					String result="Remove from table";
					if(theTable.getLoadedAt(row))
						result = (String)JOptionPane.showInputDialog(theParentPanel, "Select Remove Option", "", 
								JOptionPane.PLAIN_MESSAGE, null, optionsLoaded, "Remove Method");
					
					if(result != null) {
						if(result.equals("Remove from database") || result.equals("Remove from database and table")) {
							CompileMain.PrtSpMsg(1, "Removing Method '" + methodName + "' from database...");
							removeMethod(methodName, prefixName);
							CompileMain.PrtSpMsg(1, "Method removed");
							theTable.validateMethods(true);
						}
						if(result.equals("Remove from database and table") || result.equals("Remove from table")) {
							theTable.removeRow(theTable.getSelectedRow());
						}
						((AbstractTableModel)theTable.getModel()).fireTableDataChanged();
					}
				}
				catch(Exception e) {
					ErrorReport.prtReport(e, "Error removing method");
				}
			}
		});
		
		Dimension d = btnRemove.getPreferredSize();
		btnRemove.setMaximumSize(d);
		btnRemove.setMinimumSize(d);
		btnEdit.setMaximumSize(d);
		btnEdit.setMinimumSize(d);
		btnAdd.setMaximumSize(d);
		btnAdd.setMinimumSize(d);
		
		btnAddGroups = new JButton("Add New Clusters");
		//btnAddGroups.setBackground(Globals.FUNCTIONCOLOR);
		btnAddGroups.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if(theParentPanel.isValid()) {
					theParentPanel.saveCPAVE();
					if(theParentPanel.isDatabaseLoaded()) {
						theParentPanel.getParentFrame().getParentMain().addNewMethods();
						
						theTable.validateMethods(true);
						((AbstractTableModel)theTable.getModel()).fireTableDataChanged();
					}
					else {
						System.err.println("Error: Database not loaded");
					}
				}
			}
		});
		
		btnAddPCC = new JButton("Add PCC to Clusters");
		//btnAddGroups.setBackground(Globals.FUNCTIONCOLOR);
		btnAddPCC.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if(theParentPanel.isValid()) {
					if(theParentPanel.isDatabaseLoaded()) {
						theParentPanel.getParentFrame().getParentMain().addPCC();
					}
					else {
						System.err.println("Error: Database not loaded");
					}
				}
			}
		});
		setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
		setBackground(Globals.BGCOLOR);
		
		sPane = new JScrollPane(theTable);
		sPane.setBackground(Globals.BGCOLOR);
		sPane.getViewport().setBackground(Globals.BGCOLOR);
		theTable.getTableHeader().setBackground(Globals.BGCOLOR);
		ScrollBarUI tUI = new BasicScrollBarUI() {
		    protected JButton createDecreaseButton(int orientation) {
		        JButton button = super.createDecreaseButton(orientation);
		        button.setBackground(Globals.BGCOLOR);
		        return button;
		    }

		    protected JButton createIncreaseButton(int orientation) {
		        JButton button = super.createIncreaseButton(orientation);
		        button.setBackground(Globals.BGCOLOR);
		        return button;
		    }

		};

		sPane.getHorizontalScrollBar().setBackground(Globals.BGCOLOR);
		sPane.getVerticalScrollBar().setBackground(Globals.BGCOLOR);
		sPane.getHorizontalScrollBar().setUI(tUI);
		sPane.getVerticalScrollBar().setUI(tUI);
		
		addEditRmPanel = CompilePanel.getPanel(false);
		addEditRmPanel.add(Box.createVerticalStrut(15));
		addEditRmPanel.add(btnAdd);
		addEditRmPanel.add(Box.createVerticalStrut(5));
		addEditRmPanel.add(btnEdit);
		addEditRmPanel.add(Box.createVerticalStrut(5));
		addEditRmPanel.add(btnRemove);
		addEditRmPanel.add(Box.createVerticalStrut(15));
		addEditRmPanel.setMaximumSize(addEditRmPanel.getPreferredSize());
		addEditRmPanel.setMinimumSize(addEditRmPanel.getPreferredSize());
		
		mainPanel = CompilePanel.getPanel(false);
		mainPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
		
		JPanel row = CompilePanel.getPanel(true);
		row.add(sPane);
		row.add(Box.createHorizontalStrut(5));
		row.add(addEditRmPanel);
		d = row.getMaximumSize();
		d.height = addEditRmPanel.getMaximumSize().height;
		row.setMaximumSize(d);
		
		mainPanel.add(lblMethods);
		mainPanel.add(Box.createVerticalStrut(10));
		mainPanel.add(row);
		
		add(new JSeparator());
		add(Box.createVerticalStrut(10));
		add(mainPanel);	
		add(Box.createVerticalStrut(10));
		
		row = CompilePanel.getPanel(true);
		row.add(btnAddGroups);
		row.add(Box.createHorizontalStrut(10));
		row.add(btnAddPCC);
		add(row);
	}
	
	public void removeMethod(String methodName, String methodPrefix) {
		try {

			DBConn cmpDBC = CompileMain.getDBConnection(theParentPanel);

			ResultSet rset = cmpDBC.executeQuery("SELECT PMid FROM pog_method WHERE PMstr LIKE'" + 
					methodName + "' AND prefix LIKE'" + methodPrefix + "'");
			if(!rset.next()) {
				CompileMain.PrtWarn("Method table does not exist");
				rset.close();
				return;
			}
			
			int PMid = rset.getInt(1);
			rset.close();
			/// CAS 10/25/12
			CompileMain.PrtSpMsg(2, "Remove method from sequence table");
			if (cmpDBC.tableHasColumn("unitrans", methodPrefix))
				cmpDBC.executeUpdate("ALTER TABLE unitrans DROP " + methodPrefix);
			
			int count = cmpDBC.executeCount("SELECT count(*) FROM pog_method");
			if (count==0) return;
			
			if (count==1) {
				CompileMain.PrtSpMsg(2, "Truncate method, group, member tables");
				cmpDBC.executeUpdate("TRUNCATE TABLE pog_method");
				cmpDBC.executeUpdate("TRUNCATE TABLE pog_groups");
				cmpDBC.executeUpdate("TRUNCATE TABLE pog_members");
			}
			else {
				CompileMain.PrtSpMsg(2, "Remove method");
				cmpDBC.executeUpdate("DELETE FROM pog_method where PMid = " + PMid);
				count = cmpDBC.executeCount("SELECT COUNT(*) FROM pog_method");
				cmpDBC.executeUpdate("ALTER TABLE pog_method AUTO_INCREMENT = " + count+1);
				
				CompileMain.PrtSpMsg(2, "Remove members");
				cmpDBC.executeUpdate("DELETE pog_members.* " +
									"FROM pog_members, pog_groups " +
									"WHERE pog_groups.pgid=pog_members.pgid AND pog_groups.pmid=" + PMid);
				count = cmpDBC.executeCount("SELECT COUNT(*) FROM pog_members");
				cmpDBC.executeUpdate("ALTER TABLE pog_members AUTO_INCREMENT = " + count+1);
				
				CompileMain.PrtSpMsg(2, "Remove groups");
				cmpDBC.executeUpdate("DELETE FROM pog_groups where PMid = " + PMid);
				count = cmpDBC.executeCount("SELECT COUNT(*) FROM pog_groups");
				cmpDBC.executeUpdate("ALTER TABLE pog_groups AUTO_INCREMENT = " + count+1);
			}
			new Summary(0, cmpDBC, theParentPanel);
		} catch (Exception e) {
			ErrorReport.die(e, "deleting PMid");
		}
	}
	
	public void setProjectSelected(boolean selected) {
//		lblMethods.setEnabled(selected);
		btnAdd.setEnabled(selected);
		btnEdit.setEnabled(selected);
		btnRemove.setEnabled(selected);
		theTable.setEnabled(selected);
		btnAddGroups.setEnabled(selected);
		btnAddPCC.setEnabled(selected);
		
		if(selected)
			updateTableButtons();
		else
			clearData();
	}
	
	public void clearData() {
		theTable.clearTable();
	}
	
	public int getSelectedRow() { return theTable.getSelectedRow(); }	
	public int getNumRows() { return theTable.getRowCount(); }
	public boolean isMethodLoadedAt(int row) { return theTable.getLoadedAt(row); }
	public String getMethodNameAt(int row) { return (String)theTable.getValueAt(row, 0); }
	public String getMethodPrefixAt(int row) { return (String)theTable.getValueAt(row, 1); }
	public String getMethodTypeAt(int row) { return (String)theTable.getValueAt(row, 2); }
	public String getCommentAt(int row) { return (String)theTable.getValueAt(row, 3); }
	public String getSettingsAt(int row) { return (String)theTable.getValueAt(row, 4); }
	public void validateMethods(boolean reload) { theTable.validateMethods(reload); }
	
	public void setRow(int row, String methodName, String methodType, String prefix, String comment, String settings) {
		theTable.setRow(row, methodName, methodType, prefix, comment, settings);
	}
	
	public void addRow(String methodName, String methodType, String prefix, String comment, String settings) {
		theTable.addRow(methodName, methodType, prefix, comment, settings);
	}
	
	public void clearAllLoaded() {
		theTable.clearLoaded();
		updateTable();
	}
	
	public void updateTable() {
		((AbstractTableModel)theTable.getModel()).fireTableDataChanged();
	}
	
	private void updateTableButtons() {
		if(theTable.getSelectedRowCount() > 0) {
			btnEdit.setEnabled(true);
			btnRemove.setEnabled(true);
		}
		else {
			btnEdit.setEnabled(false);
			btnRemove.setEnabled(false);
		}
	}
	
	public void resizeEvent(ComponentEvent e) {
	}

	private CompilePanel theParentPanel = null;
	private Vector<String> theLoadedPrefixes = null;
	private JScrollPane sPane = null;
	private JPanel addEditRmPanel = null;
	private JPanel mainPanel = null;
	private MethodTable theTable = null;
	private JButton btnAdd = null;
	private JButton btnEdit = null;
	private JButton btnRemove = null;
	private JLabel lblMethods = null;
	private JButton btnAddGroups = null;
	private JButton btnAddPCC = null;
	
	private class MethodTable extends JTable {
		private static final long serialVersionUID = -4484804841714567031L;

		public MethodTable() {
	    	theModel = new MethodTableModel();
	    	
	        setAutoCreateColumnsFromModel( true );
	       	setColumnSelectionAllowed( false );
	       	setCellSelectionEnabled( false );
	       	setRowSelectionAllowed( true );
	       	setShowHorizontalLines( false );
	       	setShowVerticalLines( true );	
	       	setIntercellSpacing ( new Dimension ( 1, 0 ) );
	       	setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
	       	setOpaque(true);

	       	setModel(theModel);
	       	setDefaultRenderer(String.class, new TheRenderer());
		}
		
		public Object getValueAt(int row, int col) {
			return theModel.getValueAt(row, col); 
		}
		
		public boolean getLoadedAt(int row) { return theModel.getIsLoadedAt(row); }
		public String getMethodNameAt(int row) { return theModel.getMethodNameAt(row); }
		public String getPrefixAt(int row) { return theModel.getPrefixAt(row); }
		public String getMethodTypeAt(int row) { return theModel.getMethodTypeAt(row); }
		public String getCommentAt(int row) { return theModel.getCommentAt(row); }
		public String getSettingsAt(int row) { return theModel.getSettingsAt(row); }
		
		public void addRow(String name, String method, String prefix, String comment, String settings) {
			theModel.addRow(name, method, prefix, comment, settings);
		}
		
		public void setRow(int row, String name, String method, String prefix, String comment, String settings) {
			theModel.setRow(row, name, method, prefix, comment, settings);
		}
		
		public void removeRow(int row) {
			theModel.removeRow(row);
		}
		
		public void clearLoaded() {
			theModel.clearLoadedMethods();
		}
		
		public void clearTable() {
			theModel.clearTable();
			theModel.fireTableDataChanged();
		}
		
		public void validateMethods(boolean reload) { theModel.validateMethods(reload); }
		
		private MethodTableModel theModel = null;
		
		private class MethodTableModel extends AbstractTableModel {
			private static final long serialVersionUID = 1757554491364875137L;
			
			public int getColumnCount() { return COLUMN_NAMES.length; }
			public int getRowCount() { return rows.length; }
			public String getColumnName(int pos) { return COLUMN_NAMES[pos]; }

			public boolean getIsLoadedAt(int row) { return rows[row].isLoaded(); }
			public String getMethodNameAt(int row) { return rows[row].getMethodName(); }
			public String getMethodTypeAt(int row) { return rows[row].getMethodType(); }
			public String getPrefixAt(int row) { return rows[row].getPrefix(); }
			public String getCommentAt(int row) { return rows[row].getComment(); }
			public String getSettingsAt(int row) { return rows[row].getSettings(); }
			
			public Object getValueAt(int row, int column) {
				if(column == 0)
					return rows[row].getMethodName();
				if(column == 1)
					return rows[row].getPrefix();
				if(column == 2) {
					return rows[row].getMethodType();
				}
				if(column == 3)
					return rows[row].getComment();
				return rows[row].getSettings();
			}
			
			public Class<?> getColumnClass(int col) {
				return String.class;
			}
			
			public void addRow(String methodName, String methodType, String prefix, String comment, String settings) {
				RowData [] oldTable = rows;
				
				rows = new RowData[oldTable.length + 1];
				for(int x=0; x<oldTable.length; x++)
					rows[x] = oldTable[x];
				rows[rows.length - 1] = new RowData(methodName, methodType, prefix, comment, settings);
			}
			
			public void setRow(int row, String methodName, String methodType, String prefix, String comment, String settings) {
				if (row == -1) return; // CAS 4/11/13
				rows[row].setMethodName(methodName);
				rows[row].setMethodType(methodType);
				rows[row].setPrefix(prefix);
				rows[row].setComment(comment);
				rows[row].setSettings(settings);
			}
			
			public void clearLoadedMethods() {
				for(int row=0; row<rows.length; row++) {
					rows[row].setLoaded(false);
				}
			}
			
			public void validateMethods(boolean loadFromDB) {
				try {
					if(theLoadedPrefixes == null || loadFromDB) {
						String dbName = theParentPanel.getProjectPanel().getDBName();
						if(dbName != null && dbName.length() > 0 ) {
							theLoadedPrefixes = CompilePanel.getLoadedMethodPrefixes(dbName);
						}
					}
					for(int row=0; row<rows.length; row++) {
						rows[row].setLoaded(theLoadedPrefixes.contains(rows[row].getPrefix()));
					}
				}
				catch(Exception e) {
					ErrorReport.prtReport(e, "Error validating method");
				}
			}
			
			public void removeRow(int row) {
				RowData [] oldTable = rows;
				int index = 0;
				
				rows = new RowData[oldTable.length - 1];
				for(int x=0; x<oldTable.length; x++) {
					if(x != row) {
						rows[index] = oldTable[x];
						index++;
					}
				}
			}
			
			public void clearTable() {
				rows = new RowData[0];
			}
			
			private final String [] COLUMN_NAMES = { "Name", "Prefix", "Method", "Remark" };
			private RowData [] rows = new RowData[0];
			
			private class RowData {
				public RowData(String methodName, String methodType, String prefix, String comment, String settings) {
					strMethodName = methodName;
					strMethodType = methodType;
					strPrefix = prefix;
					strComment = comment;
					strSettings = settings;
				}
				
				public String getMethodName() { return strMethodName; }
				public String getMethodType() { return strMethodType; }
				public String getComment() { return strComment; }
				public String getPrefix() { return strPrefix; }
				public String getSettings() { return strSettings; }
				public boolean isLoaded() { return bLoaded; }
				
				public void setMethodName(String methodName) { strMethodName = methodName; }
				public void setMethodType(String methodType) { strMethodType = methodType; }
				public void setPrefix(String prefix) { strPrefix = prefix; }
				public void setComment(String comment) { strComment = comment; }
				public void setSettings(String settings) { strSettings = settings; }
				public void setLoaded(boolean isLoaded) { bLoaded = isLoaded; }
				
				private String strMethodName = "";
				private String strPrefix = "";
				private String strMethodType = "";
				private String strComment = "";
				private String strSettings = "";
				private boolean bLoaded = false;
			}
			
		}
	}
	
	private class TheRenderer extends DefaultTableCellRenderer {
		private static final long serialVersionUID = 6195418129152499449L;

		public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
			Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
			Font oldFont = c.getFont();
			Font newFont = null;
				
			if(theTable.getLoadedAt(row)) {
				newFont = new Font(oldFont.getFontName(), Font.ITALIC, oldFont.getSize());
				c.setFont(newFont);
			}
			return c;
		}
	}

}
